# p = (4, 5)
# x, y = p
# print(x, y)
#
# data = ['ACME', 50, 91.1, (2012, 12, 21)]
# name, shares, price, date = data
#
# # 如果有不想要的值，直接用下划线代替后舍弃
# _, _, score, _, time = data
import collections

# 星号可以切分多个值出来 被切分出来的是list
# recode = ('dave', 'dave@example.com', '777-888-999', '111-222-333')
# name, email, *phone_numbers = recode
# print(name, email, phone_numbers)
# grades = list(range(0, 10))
# # for num in range(1, 10):
# #     grades.append(num)
# first, *middle, last = grades
# # print(first, middle, last)
#
# array1 = [('foo', 1, 2), ('bar', 'hello'), ('foo', 3, 4)]


# def do_foo(x, y):
#     print('foo', x, y)
#
#
# def do_bar(s):
#     print('bar', s)
#
#
# for item in array1:
#     tag, *args = item
#     if tag == 'foo':
#         do_foo(*args)
#     elif tag == 'bar':
#         do_bar(*args)
#
# data = ['ACME', 50, 91.1, (2012, 12, 21)]
# name, *_, (*_, year) = data


# def isum(array):
#     head, *tail = array
#     if not tail:
#         return head
#     else:
#         return head + isum(tail)
#
#
# print(isum(grades))
# 借助deque这个数据结构保留最后N个元素 如果不指定长度则为无限长
# from collections import deque
#
# q = deque(maxlen=3)
# q.append(1)
# q.append(2)
# q.append(3)
# print(q)
# q.append(4)
# print(q)

# 借助堆保留最大/最小的N个元素
# import heapq
# import random
#
# # random_numbers = random.sample(range(1, 101), 10)
# # print(random_numbers)
# # print(heapq.nlargest(3, random_numbers))
# # print(heapq.nsmallest(3, random_numbers))
# random_array = random.sample(range(-100, 101), 10)
# print(random_array)
# heap = list(random_array)
# heapq.heapify(heap)
# print(heap)


# 优先级队列
# import heapq
#
#
# class PriorityQueue:
#     def __init__(self):
#         self._queue = []
#         self._index = 0
#
#     def push(self, item, priority):
#         heapq.heappush(self._queue, (priority, self._index, item))
#         self._index += 1
#
#     def pop(self):
#         return heapq.heappop(self._queue)[-1]
#
#
# class Item:
#     def __init__(self, name):
#         self.name = name
#
#     def __repr__(self):
#         return 'Item({})'.format(self.name)
#
#
# q = PriorityQueue()
# q.push(Item('foo'), 1)
# q.push(Item('bar'), 5)
# q.push(Item('spam'), 4)
# q.push(Item('grok'), 1)
# print(q.pop())
# print(q.pop())
# print(q.pop())
# print(q.pop())
#
# from collections import defaultdict
#
#
# from networkx.algorithms.assortativity import pairs
#
#
# d = defaultdict(list)
# d['a'].append(1)
# d['a'].append(2)
# d['a'].append(3)
# d['a'].append(3)
# d['a'].append(2)
# d['a'].append(2)
# d['c'].append(1)
# d['b'].append(4)
#
# print(d)
# d = defaultdict(set)
# d['a'].add(5)s
# d['a'].add(5)
# d['a'].add(6)
# d['b'].add(7)
# print(d['a'])
# d = defaultdict(list)
# for key, value in pairs:
#     d[key].append(value)
#
# OrderdeDict会维持插入时的顺序，但自身内存消耗比较多，因为内部维护了一个根据插入顺序排序的双向链表
# 关于字典的运算
# prices = [(91.1, 'AAPL'), (89.1, 'MSFT'), (70.1, 'FB',), (505.1, 'GOOG')]
# reversed_prices = [(name, price) for price, name in prices]
# print(reversed_prices)
# prices = {'AAPL': 91.1, 'MSFT': 89.1, 'FB': 70.1, 'GOOG': 505.1}
# max_prices = max(zip(prices.values(), prices.keys()))
# min_prices = min(zip(prices.values(), prices.keys()))
# print(min_prices)
# print(max_prices)
# def dedupe(items):
#     seen = set()  # 每次调用都重新创建
#     for item in items:  # 从头开始执行循环
#         if item not in seen:
#             seen.add(item)  # 在yield后立即执行
#             yield item  # 暂停并返回值
#   生成器每次会执行到yield，随后再继续执行
# def debug_dedupe(items):
#     seen = set()
#     print(f"初始化: seen = {seen}")
#
#     for i, item in enumerate(items):
#         print(f"循环 {i}: 检查 item = {item}, seen = {seen}")
#
#         if item not in seen:
#             print(f"  → 准备 yield {item}")
#             yield item
#             print(f"  ← 从 yield 恢复，现在添加 {item} 到 seen")
#             seen.add(item)
#         else:
#             print(f"  → 跳过 {item} (已在 seen 中)")
#
#
# # 手动逐步执行
# items = [1, 2, 2, 3]
# gen = debug_dedupe(items)
# print("=== 第一次调用 next() ===")
# val1 = next(gen)
# print(f"得到: {val1}")
#
# print("\n=== 第二次调用 next() ===")
# val2 = next(gen)
# print(f"得到: {val2}")
#
# print("\n=== 第三次调用 next() ===")
# val3 = next(gen)
# print(f"得到: {val3}")
#
# print("\n=== 第四次调用 next() ===")
# val4 = next(gen)
# print(f"得到: {val4}")

# def dedupe(items):
#     seen = set()
#     for item in items:
#         if item not in seen:
#             yield item
#             seen.add(item)
#
#
# # 利用set去重，但是使用yield保证返回顺序
# a = [1, 5, 2, 1, 9, 1, 5, 10]
# print(list(dedupe(a)))
# print(set(a))
# 使用*把a传进去，相当于把a拆成多个参数
# a = slice(2, 50, 2)
# s = 'helloworld'
# a.indices(len(s))
# # 这样就不会出现边界IndexError异常问题
# for i in range(*a.indices(len(s))):
#     print(s[i])


# 序列中出现次数最多的元素
# from collections import Counter
#
# words = [
#     'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes',
#     'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around', 'the',
#     'eyes', "don't", 'look', 'around', 'the', 'eyes', 'look', 'into',
#     'my', 'eyes', "you're", 'under'
# ]
# word_counts = Counter(words)
# print(dir(word_counts))


# operator 模块的 itemgetter 函数可用于调用对象的特定项，可用于max，min和需要排序的字典
# from operator import itemgetter
#
# rows = [
#     {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
#     {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
#     {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
#     {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
# ]
# rows_by_fname = sorted(rows, key=itemgetter('fname'))
# rows_by_uid = sorted(rows, key=itemgetter('uid'))
# rows_by_lfname = sorted(rows, key=itemgetter('lname', 'fname'))
# print(rows_by_lfname)
# print(rows_by_fname)
# print(rows_by_uid)
# # itemgetter 函数略快于lambda 函数
# rows_by_fname = sorted(rows, key=lambda r: r['fname'])
# rows_by_lfname = sorted(rows, key=lambda r: (r['lname'], r['fname']))
# attrgetter 函数能够获取对象属性，同样可用于max，min.同样略快于lambda
# addresses = [
#     '5412 N CLARK',
#     '5148 N CLARK',
#     '5800 E 58TH',
#     '2122 N CLARK',
#     '5645 N RAVENSWOOD',
#     '1060 W ADDISON',
#     '4801 N BROADWAY',
#     '1039 W GRANVILLE',
# ]
# counts = [0, 3, 10, 4, 1, 7, 5, 2, 9, 9, 9]
#
# items = zip(addresses, counts)
# more5 = [x for x in items if x[1] > 5]
# print(more5)


# 从字典里提取子集 直接使用字典推导更快
# prices = {
#     'ACME': 45.23,
#     'AAPL': 612.78,
#     'IBM': 205.55,
#     'HPQ': 37.20,
#     'FB': 10.75
# }
# # Make a dictionary of all prices over 200
# p1 = {key: value for key, value in prices.items() if value > 200}
# # Make a dictionary of tech stocks
# tech_names = {'AAPL', 'IBM', 'HPQ', 'MSFT'}
# p2 = {key: value for key, value in prices.items() if key in tech_names}

# 命名元组仅包括当前实例
# from collections import namedtuple
#
# Stock = namedtuple('Stock', ['name', 'shares', 'price'])
# a = Stock('ACME', 100, 123.45)
# print(dir(a))
# s = ('ACME', 50, 123.45)
# print(','.join(str(x) for x in s))
# 使用ChainMap在不创建新字典的情况下合并俩个字典，通过ChainMap查找时，会从第一个字典开始查找，如果第一个字典没有，则从第二个字典开始查找
# 通过ChainMap进行修改时，只对第一个字典进行修改
